from typing import Generator

from dify_plugin import Tool
from dify_plugin.entities.tool import ToolInvokeMessage

from tools.utils.file_utils import get_meta_data
from tools.utils.logger_utils import get_logger
from tools.utils.md_utils import MarkdownUtils
from tools.utils.mimetype_utils import MimeType
from tools.utils.param_utils import get_md_text


class MarkdownToPdfTool(Tool):
    logger = get_logger(__name__)

    def _invoke(self, tool_parameters: dict) -> Generator[ToolInvokeMessage, None, None]:
        """
        invoke tools
        """
        from xhtml2pdf import pisa

        # get parameters
        md_text = get_md_text(tool_parameters, is_strip_wrapper=True)
        try:
            html_str = self._convert_to_html(md_text)
            result_file_bytes = pisa.CreatePDF(
                src=html_str,
                dest_bytes=True,  # pass the generated bytes in return
                encoding="utf-8",
                capacity=400 * 1024 * 1024,  # 500 MB capacity limit
            )
        except Exception as e:
            self.logger.exception("Failed to convert file")
            yield self.create_text_message(f"Failed to convert markdown text to PDF file, error: {str(e)}")
            return

        yield self.create_blob_message(
            blob=result_file_bytes,
            meta=get_meta_data(
                mime_type=MimeType.PDF,
                output_filename=tool_parameters.get("output_filename"),
            ),
        )
        return

    @staticmethod
    def _convert_to_html(md_text: str) -> str:
        # convert markdown to html
        html_str = MarkdownUtils.convert_markdown_to_html(md_text)

        if not MarkdownUtils.contains_chinese(md_text) \
                and not MarkdownUtils.contains_japanese(md_text):
            return html_str

        # prepend additional CSS style

        # known available asian fonts in PDF by default (Acrobat Reader)
        # https://xhtml2pdf.readthedocs.io/en/latest/reference.html#asian-fonts-support
        # TODO: make font list configurable
        font_families = ",".join(
            [
                "Sans-serif",  # for English
                "STSong-Light",  # for Simplified Chinese
                "MSung-Light",  # for Traditional Chinese
                "HeiseiMin-W3",  # for Japanese
            ]
        )
        css_style = f"""
        <style>
            html {{
                -pdf-word-wrap: CJK;
                font-family:  "{font_families}"; 
            }}
        </style>
        """

        result = f"""
        {css_style}
        {html_str}
        """
        return result
